using Microsoft.EntityFrameworkCore;
using RAG.Domain.Entities.App;
using RAG.Domain.Repositories;
using RAG.Infrastructure.Data;
using RAG.Infrastructure.Services;
using Pgvector;
using System;

namespace RAG.Infrastructure.Repositories;

/// <summary>
/// 知识库仓储实现
/// </summary>
public class KnowledgeBaseRepository : EfRepository<KnowledgeBase>, IKnowledgeBaseRepository
{
    public KnowledgeBaseRepository(RagAIDbContext context) : base(context)
    {
    }

    /// <summary>
    /// 向量相似性搜索 - 使用HNSW索引和余弦距离
    /// </summary>
    public async Task<List<KnowledgeBase>> SearchSimilarAsync(float[] queryVector, int limit = 10, double threshold = 0.7)
    {
        try
        {
            // 1. 验证输入向量
            if (!VectorDistanceService.IsValidVector(queryVector))
            {
                throw new ArgumentException("查询向量无效");
            }

            // 2. 检查数据库中是否有数据
            var totalCount = await _context.KnowledgeBase.CountAsync();
            System.Console.WriteLine($"数据库中共有 {totalCount} 条知识库记录");
            if (totalCount == 0)
            {
                System.Console.WriteLine("数据库中没有知识库数据");
                return new List<KnowledgeBase>();
            }

            // 3. 获取查询向量统计信息
            var queryStats = VectorDistanceService.GetVectorStats(queryVector);
            System.Console.WriteLine($"查询向量统计: {queryStats}");

            // 4. 确保查询向量标准化（如果不是）
            float[] normalizedQuery = queryVector;
            if (!queryStats.IsNormalized)
            {
                System.Console.WriteLine("查询向量未标准化，正在标准化...");
                normalizedQuery = VectorDistanceService.NormalizeVector(queryVector);
                var normalizedStats = VectorDistanceService.GetVectorStats(normalizedQuery);
                System.Console.WriteLine($"标准化后向量统计: {normalizedStats}");
            }

            // 5. 创建pgvector对象
            var vector = VectorDistanceService.CreatePgVector(normalizedQuery);

            // 6. 改为：不在SQL中做阈值过滤，而是扩大候选集合 (limit * 3)，随后在应用层计算相似度再过滤与截断。
            int candidateSize = Math.Min(limit * 3, 200); // 上限防止过大
            var sql = "SELECT kb.* FROM \"KnowledgeBase\" kb ORDER BY kb.\"Embedding\" <=> {0} LIMIT {1}";

            System.Console.WriteLine($"执行HNSW候选查询 - 阈值(应用层)={threshold:F4}, 候选限制: {candidateSize}, 最终期望: {limit}");
            var candidateResults = await _context.KnowledgeBase
                .FromSqlRaw(sql, vector, candidateSize)
                .Include(kb => kb.Chunk!)
                .ThenInclude(c => c!.Document)
                .ToListAsync();
            System.Console.WriteLine($"候选返回 {candidateResults.Count} 条");

            // 应用层计算并过滤
            var filtered = new List<(KnowledgeBase kb, double sim)>();
            foreach (var kb in candidateResults)
            {
                var sim = VectorDistanceService.CalculateCosineSimilarity(normalizedQuery, kb.Embedding);
                if (sim >= threshold)
                {
                    filtered.Add((kb, sim));
                }
            }

            var ordered = filtered
                .OrderByDescending(t => t.sim)
                .Take(limit)
                .Select(t => t.kb)
                .ToList();

            System.Console.WriteLine($"应用层过滤后剩余 {ordered.Count} 条 (阈值={threshold:F4})");
            await LogSearchResults(normalizedQuery, ordered, "最终");
            return ordered;
        }
        catch (Exception ex)
        {
            System.Console.WriteLine($"向量搜索异常: {ex.Message}");
            System.Console.WriteLine($"异常堆栈: {ex.StackTrace}");

            // 异常情况下，尝试基础查询作为备选
            try
            {
                var fallbackResults = await _context.KnowledgeBase
                    .Include(kb => kb.Chunk!)
                    .ThenInclude(c => c!.Document)
                    .Take(Math.Min(limit, 3))
                    .ToListAsync();

                System.Console.WriteLine($"异常情况下返回前 {fallbackResults.Count} 条数据");
                return fallbackResults;
            }
            catch (Exception fallbackEx)
            {
                System.Console.WriteLine($"备用查询也失败: {fallbackEx.Message}");
                return new List<KnowledgeBase>();
            }
        }
    }

    /// <summary>
    /// 记录搜索结果调试信息
    /// </summary>
    private Task LogSearchResults(float[] queryVector, List<KnowledgeBase> results, string resultType)
    {
        for (int i = 0; i < Math.Min(results.Count, 3); i++)
        {
            var item = results[i];
            var similarity = VectorDistanceService.CalculateCosineSimilarity(queryVector, item.Embedding);
            var distance = VectorDistanceService.CalculateCosineDistance(queryVector, item.Embedding);
            var storedStats = VectorDistanceService.GetVectorStats(item.Embedding);

            System.Console.WriteLine($"{resultType}结果 {i + 1}:");
            System.Console.WriteLine($"  余弦相似度={similarity:F4}, 余弦距离={distance:F4}");
            System.Console.WriteLine($"  存储向量统计: {storedStats}");
            System.Console.WriteLine($"  内容='{item.Content?[..Math.Min(50, item.Content?.Length ?? 0)]}'");
        }
        return Task.CompletedTask;
    }

    /// <summary>
    /// 记录最相似的记录（用于调试）
    /// </summary>
    private async Task LogTopSimilarRecords(float[] queryVector, int limit)
    {
        try
        {
            var vector = VectorDistanceService.CreatePgVector(queryVector);
            var sqlNoThreshold = @"
                SELECT kb.*
                FROM ""KnowledgeBase"" kb
                ORDER BY kb.""Embedding"" <=> {0}
                LIMIT {1}";

            var topResults = await _context.KnowledgeBase
                .FromSqlRaw(sqlNoThreshold, vector, limit)
                .Include(kb => kb.Chunk!)
                .ThenInclude(c => c!.Document)
                .ToListAsync();

            System.Console.WriteLine($"最相似的 {topResults.Count} 条记录:");
            await LogSearchResults(queryVector, topResults, "最相似");
        }
        catch (Exception ex)
        {
            System.Console.WriteLine($"记录最相似记录时出错: {ex.Message}");
        }
    }

    /// <summary>
    /// 根据文档类型搜索
    /// </summary>
    public async Task<List<KnowledgeBase>> GetByDocumentTypeAsync(string documentType)
    {
        return await _context.KnowledgeBase
            .Include(kb => kb.Chunk)
            .Where(kb => kb.DocumentType == documentType)
            .OrderByDescending(kb => kb.CreatedAt)
            .ToListAsync();
    }

    /// <summary>
    /// 根据嵌入类型搜索
    /// </summary>
    public async Task<List<KnowledgeBase>> GetByEmbeddingTypeAsync(string embeddingType)
    {
        return await _context.KnowledgeBase
            .Include(kb => kb.Chunk)
            .Where(kb => kb.EmbeddingType == embeddingType)
            .OrderByDescending(kb => kb.CreatedAt)
            .ToListAsync();
    }

    /// <summary>
    /// 根据标题模糊搜索
    /// </summary>
    public async Task<List<KnowledgeBase>> SearchByTitleAsync(string title)
    {
        return await _context.KnowledgeBase
            .Include(kb => kb.Chunk)
            .Where(kb => EF.Functions.Like(kb.Title, $"%{title}%"))
            .OrderByDescending(kb => kb.CreatedAt)
            .ToListAsync();
    }

    /// <summary>
    /// 根据内容模糊搜索
    /// </summary>
    public async Task<List<KnowledgeBase>> SearchByContentAsync(string content)
    {
        return await _context.KnowledgeBase
            .Include(kb => kb.Chunk)
            .Where(kb => EF.Functions.Like(kb.Content, $"%{content}%"))
            .OrderByDescending(kb => kb.CreatedAt)
            .ToListAsync();
    }

    /// <summary>
    /// 根据块ID获取知识库条目
    /// </summary>
    public async Task<List<KnowledgeBase>> GetByChunkIdAsync(Guid chunkId)
    {
        return await _context.KnowledgeBase
            .Include(kb => kb.Chunk)
            .Where(kb => kb.ChunkId == chunkId)
            .ToListAsync();
    }

    /// <summary>
    /// 删除指定块的所有知识库条目
    /// </summary>
    public async Task<int> DeleteByChunkIdAsync(Guid chunkId)
    {
        var entities = await _context.KnowledgeBase
            .Where(kb => kb.ChunkId == chunkId)
            .ToListAsync();

        if (entities.Any())
        {
            _context.KnowledgeBase.RemoveRange(entities);
            await _context.SaveChangesAsync();
        }

        return entities.Count;
    }

    /// <summary>
    /// 获取知识库总条数
    /// </summary>
    public Task<int> CountAllAsync()
    {
        return _context.KnowledgeBase.CountAsync();
    }

    /// <summary>
    /// 按嵌入类型分组统计数量
    /// </summary>
    public async Task<Dictionary<string, int>> CountByEmbeddingTypeAsync()
    {
        return await _context.KnowledgeBase
            .GroupBy(k => k.EmbeddingType)
            .Select(g => new { g.Key, Cnt = g.Count() })
            .ToDictionaryAsync(x => x.Key ?? string.Empty, x => x.Cnt);
    }

    /// <summary>
    /// 分页查询
    /// </summary>
    public async Task<(List<KnowledgeBase> Items, int Total)> QueryAsync(string? keyword, Guid? documentId, string? documentType, int page, int pageSize)
    {
        if (page <= 0) page = 1;
        if (pageSize <= 0) pageSize = 10;
        var query = _context.KnowledgeBase
            .Include(k => k.Chunk!)
            .ThenInclude(c => c.Document)
            .AsQueryable();

        if (!string.IsNullOrWhiteSpace(keyword))
        {
            var kw = keyword.Trim();
            query = query.Where(k => k.Title.Contains(kw) || k.Content.Contains(kw));
        }
        if (documentId.HasValue)
        {
            query = query.Where(k => k.Chunk!.Document.Id == documentId.Value);
        }
        if (!string.IsNullOrWhiteSpace(documentType))
        {
            query = query.Where(k => k.DocumentType == documentType);
        }

        var total = await query.CountAsync();
        var items = await query
            .OrderByDescending(k => k.CreatedAt)
            .Skip((page - 1) * pageSize)
            .Take(pageSize)
            .ToListAsync();

        return (items, total);
    }
}
